package org.hs.phd.common.framesource;

import com.googlecode.javacv.cpp.opencv_core.IplImage;

public class DefaultFramePlayer implements FramePlayer, Runnable {

    private enum State {

        PLAYING, PAUSED, STOPPED, RESET
    };
    private final FrameSource frameSource;
    private volatile State state;
    private Thread playerThread;
    private final int interFrameMilliseconds;
    private final FrameProcessor frameProcessor;

    public DefaultFramePlayer(FrameSource frameSource, int interFrameMilliseconds, FrameProcessor frameProcessor) {
        this.frameSource = frameSource;
        this.interFrameMilliseconds = interFrameMilliseconds;
        this.frameProcessor = frameProcessor;

        state = State.PAUSED;
        playerThread = new Thread(this);
        playerThread.start();
    }

    @Override
    public void play() {
        checkPausedState("play");
        setStateAndNotify(State.PLAYING);
    }

    @Override
    public void pause() {
        this.state = State.PAUSED;
    }

    @Override
    public void reset() {
       this.state = State.RESET;
     }

    private synchronized void setStateAndNotify(State state) {
        this.state = state;
        notifyAll();
    }

    @Override
    public void stop() {
        setStateAndNotify(State.STOPPED);
    }

    @Override
    public void stepNext() {
        checkPausedState("stepNext");
        processNextFrame();
    }

    @Override
    public void stepPrevious() {
        checkPausedState("stepPrevious");
        processPreviousFrame();
    }

    private void checkPausedState(String message) {
        if (state != State.PAUSED) {
            throw new IllegalStateException(message + " only possible if player is in paused state");
        }
    }

    @Override
    public boolean isPaused() {
        return state == State.PAUSED;
    }

    @Override
    public void run() {
        while (state != State.STOPPED) {
            
 
            while (state == State.PAUSED) {
                try {
                    synchronized (this) {
                    	wait();
                    }
                } catch (InterruptedException e) {
                    //do nothing
                }
            }

            if(state == State.RESET){
                frameSource.reset();
                state = State.PAUSED;
                continue;
            }

            processNextFrame();
        }
    }

    public boolean isFinished() {
        return state == State.STOPPED;
    }

    private void processNextFrame() {
        ImageSequenceFrame frame = frameSource.loadNextFrame();

        processFrame(frame);
    }

    private void processPreviousFrame() {
        ImageSequenceFrame frame = frameSource.loadPreviousFrame();

        processFrame(frame);
    }

    private void processFrame(ImageSequenceFrame frame) {
        if (frame != null) {
            frameProcessor.process(frame);
            try {
                Thread.sleep(interFrameMilliseconds);
            } catch (InterruptedException e) {
                // ignore
            }
        }

    }
}
